package cn.ly.rabbit.config;

import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.log4j.Log4j2;
import org.springframework.amqp.core.*;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter;
import org.springframework.amqp.support.converter.MessageConverter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * 生产者：只关注 交换器名字、路由键（在业务中指定路由：sb.lies）
 * 所以此处只用配置：交换器的【名字】即可
 * 但为了确认消息不丢失，故配置了【全局】的：失败通知、发布者确认
 *
 * 而消费者中，要配置交换器、队列、还有交换器与队列的绑定建：如sb.*
 */
@Log4j2
@Configuration
public class RabbitConfig {

    //简单队列，默认使用RabbitMq默认的Direct交换器，其routeKey与该queueName一致
    public static final String Simple_Queue_Name = "hello.queue";
    public static final String Direct_Exchange_Name="myDirect.exchange";
    public static final String Topic_Exchange_Name="myTopic.exchange";






    //我在消费者处指定的：Topic交换器 与 B_Queue队列绑定的绑定键：规则。生产者指定路由键时，需参照下
    public static final String B_Queue_RouteKey="test.b.*";
    //死信交换器1：Topic类型
    public static final String DLX_Exchange_Name="myDlx.exchange";
    //死信交换器1 与 死信队列2的绑定键规则。延时支付业务中，生产者指定死信的路由键时，需参照下
    public static final String Order_Queue_RouteKey="dlx.order.#";


    //死信交换器2：Direct类型
    public static final String DLX_Delay_Exchange_Name = "myDlx.direct.exchange";
    public static final String Order_Queue_Name = "myOrder.queue";




    @Autowired
    private ConnectionFactory connectionFactory;
    @Bean
    public RabbitTemplate newRabbitTemplate() {
        RabbitTemplate template = new RabbitTemplate(connectionFactory);
        //全局失败通知
        template.setMandatory(true);
        //全局发送方确认
        template.setConfirmCallback(confirmCallback());
        //全局失败回调
        template.setReturnCallback(returnCallback());
        //RabbitMQ 提供了 Jackson2JsonMessageConverter 来支持消息内容 JSON 序列化与反序列化
        //消息发送者在发送消息时应设置 MessageConverter 为 Jackson2JsonMessageConverter
        template.setMessageConverter(new Jackson2JsonMessageConverter());
        return template;
    }
    //===============生产者 全局发送确认==========
    @Bean
    public RabbitTemplate.ConfirmCallback confirmCallback(){
        return new RabbitTemplate.ConfirmCallback(){
            @Override
            public void confirm(CorrelationData correlationData,
                                boolean ack, String cause) {
                if (ack) {
                    log.info("发布者确认：>>>>>>>>>>发送者确认发送给mq成功");
                } else {
                    //处理失败的消息
                    log.error(">>>>>>>>>>发送者发送给mq失败,考虑重发:"+cause);
                }
            }
        };
    }
    //===============生产者 全局失败通知==========
    @Bean
    public RabbitTemplate.ReturnCallback returnCallback(){
        return new RabbitTemplate.ReturnCallback(){
            @Override
            public void returnedMessage(Message message,
                                        int replyCode,
                                        String replyText,
                                        String exchange,
                                        String routingKey) {
//                System.out.println("失败通知：>>>>>>>>>>无法路由的消息，需要考虑另外处理。");
                String msgJson  = new String(message.getBody());
                log.error("失败通知：>>>>>>>>>>>消息丢失:exchange({}),route({}),replyCode({}),replyText({}),message:{}",
                        exchange,routingKey,replyCode,replyText,msgJson);
            }
        };
    }


}
